package com.bjpowernode.service.impl;

import com.aventrix.jnanoid.jnanoid.NanoIdUtils;
import com.bjpowernode.entity.PmsFile;
import com.bjpowernode.service.FileService;
import com.bjpowernode.service.PmsFileService;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.compress.utils.FileNameUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;


@Service
public class FileServiceImpl implements FileService {
    //将配置文件中的配置信息注入到service中，读取配置文件，使得方法中可以直接使用
    @Value("${minio.url}")
    String url;
    @Value("${minio.username}")
    String username;
    @Value("${minio.password}")
    String password;

    //注入，上传文件前需要先判断是否是相同文件
    @Resource
    PmsFileServiceImpl pmsFileServiceImpl;

    @Resource
    PmsFileService pmsFileService;

    //NanoIdUtils.randomNanoId() 表示生成一个21为随机串，这里表示来做文件名
    //StringBuilder fileName = new StringBuilder(NanoIdUtils.randomNanoId()); 使用StringBuilder是为了避免频繁创建对象，后续需要对文件名（生成的随机字符串进行拼接改造）
    @Override
    public String upload(String bucket, MultipartFile file) throws Exception  {
        //判断是否上传的是相同文件
        //取得md5 文件大小和文件类型
        String md5 = DigestUtils.md2Hex(file.getInputStream());//将文件的二进制流解析为字符串
        long size = file.getSize();
        String type = file.getContentType();
        //判断以前是否上传的是相同文件
        PmsFile pmsFile = pmsFileServiceImpl.get(md5, size, type);//判断此方法返回值是否为空
        if (null != pmsFile){
            //不为空则说明查到了该文件，说明之前上传了此文件，则不进行重复上传
            //直接返回数据库和桶里储存的文件路径
            return pmsFile.getPath();
        }
        //否则正常上传文件
        StringBuilder fileName = new StringBuilder(NanoIdUtils.randomNanoId());
        //表示拼接文件后缀（因为保存的是以图片形式保存，所以需要获取文件后缀）
        //FileNameUtils.getExtension(file.getOriginalFilename())获取文件的原始文件名的扩展名，并将其追加到fileName字符串末尾。
        fileName.append(".").append(FileNameUtils.getExtension(file.getOriginalFilename()));

        //创建minio客户端，获取文件上传到minio的服务端
        MinioClient client = MinioClient.builder()
                .endpoint(url)
                .credentials(username, password)
                .build();

        //构建在minio中上传的文件（类型，大小等等）
        PutObjectArgs args = PutObjectArgs.builder()
                .bucket(bucket)//构建文件要存储到minio的哪个桶的名称
                .contentType(file.getContentType())//构建文件类型
                .object(fileName.toString())//构建文件名称
                //构建文件内容
                //最后一一个参数表示为 较大文件进行切块上传（可以理解为断点续传）
                .stream(file.getInputStream(), file.getSize(), 0)//构建文件流，文件大小，文件是否以切块的形式传递
                .build();

        //客户端上传文件到minio
        client.putObject(args);

        //将文件在minio中的路径返回给调用处，调用处需要拿到这个图片的路径，将数据保存到icon中，保存到mysql中
        //图片在minion中的路径  桶名加文件名  /bucket/fileName
        String path = "/" + bucket + "/" + fileName.toString();

        //将上传的文件保存在数据库的file中，目的是为了之后便于对比是否有相同的文件
        pmsFile = new PmsFile(md5,size,type,path);
        pmsFileService.save(pmsFile);

        //返回路径
        return path;
    }
}
